"""
资金费率模块
获取和管理永续合约的资金费率信息
"""
import time
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from loguru import logger

try:
    import okx.PublicData as PublicData
except ImportError:
    logger.warning("okx SDK未安装，请运行: pip install okx")
    PublicData = None


class FundingRateManager:
    """资金费率管理器"""
    
    # 限速配置：10次/2s
    RATE_LIMIT_REQUESTS = 10
    RATE_LIMIT_WINDOW = 2.0  # 秒
    
    def __init__(self, sandbox: bool = True):
        """
        初始化资金费率管理器
        
        Args:
            sandbox: 是否使用模拟盘，True=模拟盘(1)，False=实盘(0)
        """
        if PublicData is None:
            raise ImportError("okx SDK未安装，请运行: pip install okx")
        
        self.sandbox = sandbox
        flag = "1" if sandbox else "0"
        
        # 初始化OKX公共数据API
        self.public_api = PublicData.PublicAPI(flag=flag)
        
        # 限速控制 - 按产品ID分别限速
        self.request_times: Dict[str, List[float]] = {}  # inst_id -> 请求时间戳列表
        
        # 数据缓存
        self.funding_rate_cache: Dict[str, Dict] = {}  # inst_id -> funding_rate_data
        self.cache_expire_time: Dict[str, datetime] = {}  # inst_id -> expire_time
        self.cache_duration = timedelta(minutes=5)  # 缓存5分钟
        
        logger.info(f"资金费率管理器已初始化 (模式: {'模拟盘' if sandbox else '实盘'})")
    
    def _check_rate_limit(self, inst_id: str):
        """
        检查并执行限速
        限速规则：10次/2s (IP + Instrument ID)
        
        Args:
            inst_id: 产品ID
        """
        now = time.time()
        
        # 初始化该产品的请求记录
        if inst_id not in self.request_times:
            self.request_times[inst_id] = []
        
        # 移除2秒前的请求记录
        self.request_times[inst_id] = [t for t in self.request_times[inst_id]
                                       if now - t < self.RATE_LIMIT_WINDOW]
        
        # 如果达到限速上限，等待
        if len(self.request_times[inst_id]) >= self.RATE_LIMIT_REQUESTS:
            oldest_request = self.request_times[inst_id][0]
            wait_time = self.RATE_LIMIT_WINDOW - (now - oldest_request)
            
            if wait_time > 0:
                logger.debug(f"触发限速 ({inst_id})，等待 {wait_time:.2f} 秒")
                time.sleep(wait_time)
                # 重新计算
                now = time.time()
                self.request_times[inst_id] = [t for t in self.request_times[inst_id]
                                               if now - t < self.RATE_LIMIT_WINDOW]
        
        # 记录本次请求
        self.request_times[inst_id].append(now)
    
    def get_funding_rate(self, inst_id: str, use_cache: bool = True) -> Dict:
        """
        获取永续合约当前资金费率
        
        Args:
            inst_id: 产品ID，如 BTC-USD-SWAP, BTC-USDT-SWAP
            use_cache: 是否使用缓存
            
        Returns:
            资金费率信息字典，包含以下字段：
            - instType: 产品类型 (SWAP)
            - instId: 产品ID
            - fundingRate: 当前资金费率
            - nextFundingRate: 预测下次资金费率
            - fundingTime: 资金费时间（毫秒时间戳）
            - nextFundingTime: 下次资金费时间（毫秒时间戳）
        """
        # 检查缓存
        if use_cache and inst_id in self.funding_rate_cache:
            expire_time = self.cache_expire_time.get(inst_id)
            if expire_time and datetime.now() < expire_time:
                logger.debug(f"从缓存获取资金费率: {inst_id}")
                return self.funding_rate_cache[inst_id]
        
        # 执行限速检查
        self._check_rate_limit(inst_id)
        
        try:
            logger.info(f"获取资金费率: {inst_id}")
            result = self.public_api.get_funding_rate(instId=inst_id)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"获取资金费率失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            data_list = result.get("data", [])
            if not data_list:
                logger.warning(f"未获取到资金费率数据: {inst_id}")
                return {}
            
            funding_data = data_list[0]
            logger.info(f"获取资金费率成功: {inst_id}, 费率={funding_data.get('fundingRate')}")
            
            # 更新缓存
            if use_cache:
                self.funding_rate_cache[inst_id] = funding_data
                self.cache_expire_time[inst_id] = datetime.now() + self.cache_duration
            
            return funding_data
            
        except Exception as e:
            logger.error(f"获取资金费率异常: {e}")
            raise
    
    def get_funding_rate_history(self, inst_id: str, 
                                 before: Optional[str] = None,
                                 after: Optional[str] = None,
                                 limit: int = 100) -> List[Dict]:
        """
        获取资金费率历史
        
        Args:
            inst_id: 产品ID
            before: 请求此时间戳之前的分页内容（毫秒时间戳）
            after: 请求此时间戳之后的分页内容（毫秒时间戳）
            limit: 返回结果数量，最大100，默认100
            
        Returns:
            历史资金费率列表
        """
        # 执行限速检查
        self._check_rate_limit(inst_id)
        
        try:
            params = {"instId": inst_id, "limit": str(limit)}
            if before:
                params["before"] = before
            if after:
                params["after"] = after
            
            logger.info(f"获取资金费率历史: {inst_id}, limit={limit}")
            result = self.public_api.funding_rate_history(**params)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"获取资金费率历史失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            history = result.get("data", [])
            logger.info(f"获取资金费率历史成功: {len(history)} 条记录")
            
            return history
            
        except Exception as e:
            logger.error(f"获取资金费率历史异常: {e}")
            raise
    
    def get_funding_rate_details(self, inst_id: str) -> Dict:
        """
        获取资金费率详细信息（包含格式化的时间和年化费率）
        
        Args:
            inst_id: 产品ID
            
        Returns:
            详细信息字典：
            - inst_id: 产品ID
            - funding_rate: 当前资金费率
            - funding_rate_pct: 当前资金费率百分比
            - next_funding_rate: 预测下次资金费率
            - next_funding_rate_pct: 预测下次资金费率百分比
            - funding_time: 资金费时间（格式化）
            - next_funding_time: 下次资金费时间（格式化）
            - annual_rate: 年化资金费率（假设每8小时一次）
        """
        funding_data = self.get_funding_rate(inst_id)
        
        if not funding_data:
            raise ValueError(f"无法获取资金费率: {inst_id}")
        
        # 提取数据
        funding_rate = float(funding_data.get("fundingRate", 0))
        next_funding_rate = float(funding_data.get("nextFundingRate", 0))
        funding_time = int(funding_data.get("fundingTime", 0))
        next_funding_time = int(funding_data.get("nextFundingTime", 0))
        
        # 计算年化费率（假设每8小时收取一次，一年365天）
        annual_rate = funding_rate * 3 * 365  # 每天3次，一年365天
        
        # 格式化时间
        funding_time_str = datetime.fromtimestamp(funding_time / 1000).strftime("%Y-%m-%d %H:%M:%S")
        next_funding_time_str = datetime.fromtimestamp(next_funding_time / 1000).strftime("%Y-%m-%d %H:%M:%S")
        
        return {
            "inst_id": inst_id,
            "funding_rate": funding_rate,
            "funding_rate_pct": funding_rate * 100,
            "next_funding_rate": next_funding_rate,
            "next_funding_rate_pct": next_funding_rate * 100,
            "funding_time": funding_time_str,
            "next_funding_time": next_funding_time_str,
            "funding_time_ts": funding_time,
            "next_funding_time_ts": next_funding_time,
            "annual_rate": annual_rate,
            "annual_rate_pct": annual_rate * 100,
        }
    
    def get_multiple_funding_rates(self, inst_ids: List[str]) -> Dict[str, Dict]:
        """
        批量获取多个产品的资金费率
        
        Args:
            inst_ids: 产品ID列表
            
        Returns:
            字典，key为产品ID，value为资金费率信息
        """
        results = {}
        
        for inst_id in inst_ids:
            try:
                funding_data = self.get_funding_rate(inst_id)
                results[inst_id] = funding_data
            except Exception as e:
                logger.error(f"获取 {inst_id} 资金费率失败: {e}")
                results[inst_id] = None
        
        return results
    
    def compare_funding_rates(self, inst_ids: List[str]) -> List[Dict]:
        """
        比较多个产品的资金费率
        
        Args:
            inst_ids: 产品ID列表
            
        Returns:
            排序后的资金费率列表（按费率从高到低）
        """
        rates = []
        
        for inst_id in inst_ids:
            try:
                details = self.get_funding_rate_details(inst_id)
                rates.append(details)
            except Exception as e:
                logger.error(f"获取 {inst_id} 资金费率失败: {e}")
        
        # 按资金费率排序（从高到低）
        rates.sort(key=lambda x: x["funding_rate"], reverse=True)
        
        return rates
    
    def clear_cache(self, inst_id: Optional[str] = None):
        """
        清除缓存
        
        Args:
            inst_id: 产品ID，如果为None则清除所有缓存
        """
        if inst_id:
            if inst_id in self.funding_rate_cache:
                del self.funding_rate_cache[inst_id]
            if inst_id in self.cache_expire_time:
                del self.cache_expire_time[inst_id]
            logger.info(f"已清除 {inst_id} 的缓存")
        else:
            self.funding_rate_cache.clear()
            self.cache_expire_time.clear()
            logger.info("已清除所有资金费率缓存")
    
    def get_cache_stats(self) -> Dict:
        """
        获取缓存统计信息
        
        Returns:
            缓存统计字典
        """
        total_cached = len(self.funding_rate_cache)
        valid_cached = sum(1 for inst_id in self.funding_rate_cache.keys()
                          if inst_id in self.cache_expire_time and
                          datetime.now() < self.cache_expire_time[inst_id])
        
        return {
            "total_cached": total_cached,
            "valid_cached": valid_cached,
            "expired_cached": total_cached - valid_cached,
            "cache_duration_minutes": self.cache_duration.total_seconds() / 60,
        }


# 便捷函数
def get_funding_rate(inst_id: str, sandbox: bool = True) -> Dict:
    """
    便捷函数：获取资金费率
    
    Args:
        inst_id: 产品ID
        sandbox: 是否使用模拟盘
        
    Returns:
        资金费率信息字典
    """
    manager = FundingRateManager(sandbox=sandbox)
    return manager.get_funding_rate(inst_id)


def get_funding_rate_details(inst_id: str, sandbox: bool = True) -> Dict:
    """
    便捷函数：获取资金费率详细信息
    
    Args:
        inst_id: 产品ID
        sandbox: 是否使用模拟盘
        
    Returns:
        详细信息字典
    """
    manager = FundingRateManager(sandbox=sandbox)
    return manager.get_funding_rate_details(inst_id)


def compare_funding_rates(inst_ids: List[str], sandbox: bool = True) -> List[Dict]:
    """
    便捷函数：比较多个产品的资金费率
    
    Args:
        inst_ids: 产品ID列表
        sandbox: 是否使用模拟盘
        
    Returns:
        排序后的资金费率列表
    """
    manager = FundingRateManager(sandbox=sandbox)
    return manager.compare_funding_rates(inst_ids)
